//
//  OPKStoreObserver.m
//  PaymentDemo
//
//  Created by ycgame on 2020/4/17.
//  Copyright © 2020 maqianzheng. All rights reserved.
//

#import "OPKStoreObserver.h"
#import "OPKConfiguration.h"
#import "OPKKeychainItem.h"

@interface OPKStoreObserver()
@property(strong)NSMutableDictionary *purchasedTransactionDictionary;
@property(nonatomic, assign)BOOL isObserver;
@property(nonatomic, strong)NSLock *lock;
@end

@implementation OPKStoreObserver

+ (OPKStoreObserver *)sharedInstance {
    static dispatch_once_t onceToken;
    static OPKStoreObserver * storeObserverSharedInstance;

    dispatch_once(&onceToken, ^{
        storeObserverSharedInstance = [[OPKStoreObserver alloc] init];
        storeObserverSharedInstance.purchasedTransactionDictionary = [[NSMutableDictionary alloc] initWithCapacity:0];
        storeObserverSharedInstance.isObserver = NO;
        storeObserverSharedInstance.lock = [[NSLock alloc] init];
    });
    return storeObserverSharedInstance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _isShouldFinish = true;
    }
    return self;
}

#pragma mark - 一些私有方法
/// 可否支付
-(BOOL)isAuthorizedForPayments {
    return [SKPaymentQueue canMakePayments];
}

- (void)becomeTransactionObserver {
    if (_isObserver) { return; }
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    _isObserver = YES;
}

- (void)resignTransactionObserver {
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
    _isObserver = NO;
}

/// 添加到支付队列
- (void)addPayment:(SKPayment *)payment {
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

/// 确认完成交易
- (void)finishTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"FT: %@", transaction.description);
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (SKPaymentTransaction *)purchasedTransactionForKey:(NSString *)key {
    return [_purchasedTransactionDictionary objectForKey:key];
}

- (void)setPurchasedTransaction:(SKPaymentTransaction *)transaction forKey:(NSString *)key {
    if (transaction == nil || key == nil) { return; }
    [_purchasedTransactionDictionary setObject:transaction forKey:key];
}

- (void)removePurchasedTransactionForKey:(NSString *)key {
    if (key == nil) { return; }
    [_purchasedTransactionDictionary removeObjectForKey:key];
}

/// 查找交易对象
- (OPKTransactionItem *)transactionItemForId:(NSString *)transactionId {
    return [OPKKeychainItem transactionItemForKey:transactionId];
}

/// 查找订单对象
- (OPKOrderItem *)orderItemWithTransaction:(SKPaymentTransaction *)transaction {
    /// 支付信息中查找
    OPKOrderItem *usernameOrderItem = (OPKOrderItem *)[self decodedString:transaction.payment.applicationUsername];
    if (usernameOrderItem != nil) {
        return usernameOrderItem;
    }
    /// 支付信息中没有，则在钥匙串中查找
    OPKOrderItem *keychainOrderItem = [OPKKeychainItem orderItemForKey:transaction.payment.productIdentifier];
    return keychainOrderItem;
}

/// 生成交易对象
- (OPKTransactionItem *)transactionItemWithTransaction:(SKPaymentTransaction *)transaction {
    if (transaction == nil) { return nil; }
    
    /// 查找对应订单
    OPKOrderItem *orderItem = [self orderItemWithTransaction:transaction];
    /// 查找订单成功，则生成 transactionItem
    if (orderItem != nil) {
        OPKTransactionItem *transactionItem = [[OPKTransactionItem alloc] init];
        transactionItem.orderItem = orderItem;
        transactionItem.transactionId = transaction.transactionIdentifier;
        transactionItem.originalTransaction = [self transactionItemWithTransaction:transaction.originalTransaction];
        return transactionItem;
    }
    
    /// 未查找到订单，则从钥匙串中查找  transactionItem
    OPKTransactionItem *keychainTransactionItem = [OPKKeychainItem transactionItemForKey:transaction.transactionIdentifier];
    if (keychainTransactionItem != nil) {
        return keychainTransactionItem;
    }
    
    /// 钥匙串中不到，则查找原始交易（自动订阅成功会生成新的transaction，但原始transaction是不会变的）
    OPKTransactionItem *originalTransactionItem = [self transactionItemWithTransaction:transaction.originalTransaction];
    /// 如果有原始交易，则返回
    if (originalTransactionItem != nil) {
        OPKTransactionItem *transactionItem = [[OPKTransactionItem alloc] init];
        transactionItem.orderItem = originalTransactionItem.orderItem;
        transactionItem.transactionId = transaction.transactionIdentifier;
        transactionItem.originalTransaction = originalTransactionItem;
        return transactionItem;
    }
    
    // 创建一个包含uid的orderItem
    OPKOrderItem *newOrderItem = [[OPKOrderItem alloc] init];
    newOrderItem.uid = [OPKKeychainItem uid];
    newOrderItem.productId = transaction.payment.productIdentifier;
    // 创建一个 new item
    OPKTransactionItem *newTransactionItem = [[OPKTransactionItem alloc] init];
    newTransactionItem.orderItem = newOrderItem;
    newTransactionItem.transactionId = transaction.transactionIdentifier;
    newTransactionItem.originalTransaction = [self transactionItemWithTransaction:transaction.originalTransaction];
    return newTransactionItem;
}

#pragma mark - 购买商品
- (void)buy:(SKProduct *)product order:(OPKOrderItem *)orderItem {
    if (![self isAuthorizedForPayments]) {
        NSLog(@"不允许购买");
        return;
    }
    
    if (product == nil || orderItem == nil) {
        NSLog(@"参数错误");
        return;
    }
    
    if ([OPKKeychainItem orderItemForKey:product.productIdentifier] != nil) {
        NSLog(@"有一笔未完成订单");
    } else {
        // 钥匙串存储
        [OPKKeychainItem setOrderItem:orderItem forKey:product.productIdentifier];
    }
    
    // 订单信息保存在支付对象中
    SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
    payment.applicationUsername = [self encodedObject:orderItem];
    
    // 添加到支付队列
    [self addPayment:payment];
}

#pragma mark - SKPaymentTransactionObserver

- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
    [_lock lock];
    // 成功交易
    NSMutableArray *purchasedTransactions = [[NSMutableArray alloc] initWithCapacity:0];
    // 失败交易
    NSMutableArray *failedTransactions = [[NSMutableArray alloc] initWithCapacity:0];
    for(SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
                // 交易中
            case SKPaymentTransactionStatePurchasing: break;
                // 延迟
            case SKPaymentTransactionStateDeferred: break;
                // 成功
            case SKPaymentTransactionStatePurchased:
                [purchasedTransactions addObject:transaction];
                break;
                // 失败
            case SKPaymentTransactionStateFailed:
                [failedTransactions addObject:transaction];
                break;
                // 恢复购买
            case SKPaymentTransactionStateRestored:
                [purchasedTransactions addObject:transaction];
                break;
            default: break;
        }
    }
    // 处理成功交易
    if (purchasedTransactions.count > 0) {
        [self handlePurchasedTransaction:purchasedTransactions];
    }
    // 处理失败交易
    if (failedTransactions.count > 0) {
        [self handleFailedTransaction:failedTransactions];
    }
    [_lock unlock];
}

- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product {
    return YES;
}

- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
    for(SKPaymentTransaction *transaction in transactions) {
        NSLog(@"[Payment Queue] %@ removed", transaction.payment.productIdentifier);
    }
}

#pragma mark - 处理交易结果
/// 苹果返回交易成功
- (void)handlePurchasedTransaction:(NSArray<SKPaymentTransaction*> *)transactions {
    if (transactions == nil || transactions.count == 0) { return; }
    // 全部成功item，给监听者传值
    NSMutableArray *transactionItems = [[NSMutableArray alloc] initWithCapacity:0];
    for (SKPaymentTransaction* transaction in transactions) {
        NSLog(@"【PAY】苹果返回交易成功：%@", transaction.payment.productIdentifier);
        // 此处为测试清空交易，请千万要不要打开
//        [self finishTransaction:transaction];
//        [OPKKeychainItem removeTransactionItemForKey:transaction.transactionIdentifier];
        // 若transactionId 或 productId 为空
        if (transaction.transactionIdentifier == nil || transaction.payment.productIdentifier == nil) { continue; }
        /// 生成交易对象
        OPKTransactionItem *transactionItem = [self transactionItemWithTransaction:transaction];
        NSLog(@"【PAY】生成交易对象：%@", transactionItem.orderItem.productId);
        // 若生成失败
        if (transactionItem == nil) { continue; }
        /// 钥匙串存储 transactionItem
        [OPKKeychainItem setTransactionItem:transactionItem forKey:transaction.transactionIdentifier];
        /// 钥匙串删除 orderItem
        [OPKKeychainItem removeOrderItemForKey:transaction.payment.productIdentifier];
        /// 将苹果返回成功交易存入内存
        [self setPurchasedTransaction:transaction forKey:transaction.transactionIdentifier];
        /// 保存交易对象，传值出去
        [transactionItems addObject:transactionItem];
    }
    /// 将交易对象发送出去
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:OPKConfirmTransactionNotification object:[transactionItems copy]];
    });
}

/// 苹果返回交易失败
- (void)handleFailedTransaction:(NSArray<SKPaymentTransaction*> *)transactions {
    if (transactions == nil || transactions.count == 0) { return; }
    for (SKPaymentTransaction* transaction in transactions) {
        /// 完成交易
        [self finishTransaction:transaction];
        /// 钥匙串移除订单对象
        [OPKKeychainItem removeOrderItemForKey:transaction.payment.productIdentifier];
        /// 钥匙串移除交易对象
        [OPKKeychainItem removeTransactionItemForKey:transaction.transactionIdentifier];
        /// 内存移除此笔交易
        [self removePurchasedTransactionForKey:transaction.transactionIdentifier];
    }
    /// 将交易对象发送出去
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:OPKFailedTransactionNotification object:nil];
    });
}


#pragma mark - 处理服务端返回结果
- (void)confirmTransactionWithId:(NSString *)transactionId result:(OPKTransactionResult)result {
    OPKTransactionItem *item = [self transactionItemForId:transactionId];
    [self confirmTransactionWithItem:item result:result];
}

- (void)confirmTransactionWithItem:(OPKTransactionItem *)transactionItem result:(OPKTransactionResult)result {
    NSLock *lock = [[NSLock alloc] init];
    [lock lock];
    switch (result) {
        case OPKTransactionResultPass:    // 验证通过
            [self handlePass:transactionItem];
            break;
        case OPKTransactionResultFail:    // 验证失败
            [self handleFail:transactionItem];
            break;
        case OPKTransactionResultUnknown:  // 未知情况
            [self handleUnknown:transactionItem];
            break;
    }
    [lock unlock];
}

// 验证通过
- (void)handlePass:(OPKTransactionItem *)transactionItem {
    SKPaymentTransaction *transaction = [self purchasedTransactionForKey:transactionItem.transactionId];
    if (transaction == nil) { return; }
    /// 非初次订阅，删除本地交易数据
    if (transactionItem.orderItem.isSubscriptionProduct == YES && transaction.originalTransaction == nil) {
        // 为初次订阅，不清除钥匙串数据
    } else {
        /// 钥匙串移除订单对象
        [OPKKeychainItem removeTransactionItemForKey:transaction.transactionIdentifier];
    }
    /// 内存移除订单对象
    [self removePurchasedTransactionForKey:transaction.transactionIdentifier];
    /// 完成交易
    [self finishTransaction:transaction];
    NSLog(@"验证通过订单 %@, %@", transaction.payment.productIdentifier, transactionItem.orderItem.uid);
}

// 验证失败
- (void)handleFail:(OPKTransactionItem *)transactionItem {
    SKPaymentTransaction *transaction = [self purchasedTransactionForKey:transactionItem.transactionId];
    if (transaction == nil) { return; }
    [OPKKeychainItem removeTransactionItemForKey:transaction.transactionIdentifier];
    [self removePurchasedTransactionForKey:transaction.transactionIdentifier];
    [self finishTransaction:transaction];
    NSLog(@"验证失败订单 %@, %@", transaction.payment.productIdentifier, transaction.transactionIdentifier);
}

// 未知情况
- (void)handleUnknown:(OPKTransactionItem *)transactionItem {
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//        [self serverCheckTranaction:transaction transactionItem:transactionItem];
//    });
}

#pragma mark Encode & Decode

- (NSString *)encodedObject:(id<NSCoding>)obj {
    if (obj == nil) { return nil;}
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:obj];
    NSString *base64String = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return base64String;
}

- (id<NSCoding>)decodedString:(NSString *)string {
    if (string == nil) { return nil;}
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters];
    id obj = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    return obj;
}

@end
